"""
公共类
"""
import os
import sys
import tkinter as tk
from tkinter import filedialog
import shutil
import zipfile
import io  # 添加io模块用于内存操作
import win32com.client as win32  # 添加win32com导入


# 选择excel文件,返回文件路径,如果没有选择文件返回空字符串

def select_file(prompt_message):  # prompt_message 提示信息
    root = tk.Tk()
    root.withdraw()
    root.attributes('-topmost', True)  # 将窗口置顶
    return filedialog.askopenfilename(title=prompt_message, filetypes=[('Excel files', '*.xlsx')])


# 判断文件夹是否存在，不存在则创建

def create_folder_if_not_exists(folder_path):  # folder_path 文件夹路径
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)


def count_files_in_zip(zip_file_path):
    if not os.path.exists(zip_file_path):
        return 0
    with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
        num_files = len(zip_ref.namelist())
    return num_files


def find_index(lst, str):
    for i in range(len(lst)):
        if str in lst[i]:
            return i
    return -1


def find_exact_match_index(lst, str):
    # 移除要查找的字符串中可能存在的扩展名
    search_name = os.path.splitext(str)[0]
    for i in range(len(lst)):
        # 移除列表中文件的扩展名后比较
        current_name = os.path.splitext(lst[i])[0]
        if current_name == search_name:
            return i
    return -1


def create_zip_file(df, directory):
    # 预先将目录文件列表转换为集合，加速查找
    arrpdf = os.listdir(directory)
    # 创建文件名到文件路径的映射，避免重复搜索
    arrpdf_dict = {file: os.path.join(directory, file) for file in arrpdf}
    
    # 创建证书代码到文件的映射，加速查找
    certificate_to_files = {}
    for file in arrpdf:
        for part in file.split('~'):
            if part not in certificate_to_files:
                certificate_to_files[part] = []
            certificate_to_files[part].append(file)
    
    nolist = []
    mail_Attachments = []

    for _, r in df.iterrows():  # 使用_代替不使用的index变量
        if not r['CertificateCode']:  # 更简洁的空字符串检查
            continue
            
        certificateCode_list = r['CertificateCode'].split(',')
        itempdflist = []
        
        for certificateCode in certificateCode_list:
            # 使用映射直接查找包含证书代码的文件
            matching_files = []
            
            # 遍历所有文件，只要文件名包含证书代码就添加到匹配列表中
            for file in arrpdf:
                if certificateCode in file:
                    matching_files.append(file)
            
            if matching_files:
                source_file = matching_files[0]  # 取第一个匹配的文件
                source_path = arrpdf_dict[source_file]
                # 将原始文件路径添加到列表中
                itempdflist.append(source_path)
            else:
                nolist.append({
                    "Item": r['Item'],
                    "CertificateCode": certificateCode
                })

        if itempdflist:
            # 创建文件名（不包含路径）
            file_name = f"{r['Item']}~{r['CertificateCode']}"
            
            # 检查第一个文件是否是压缩文件
            first_file = itempdflist[0]
            first_file_name = os.path.basename(first_file)
            if first_file_name.lower().endswith(('.zip', '.rar')):
                # 如果是压缩文件，直接将文件对象添加到mail_Attachments
                mail_Attachments.append({
                    'name': f"{file_name}{os.path.splitext(first_file_name)[1]}",
                    'path': first_file,
                    'is_file': True  # 标记为文件路径
                })
            else:
                # 如果是PDF文件，创建内存中的ZIP文件
                zip_buffer = io.BytesIO()
                
                with zipfile.ZipFile(zip_buffer, 'w') as zipf:
                    for item_pdf in itempdflist:
                        # 使用文件的原始名称作为压缩包中的名称
                        file_name_in_zip = os.path.basename(item_pdf)
                        zipf.write(item_pdf, arcname=file_name_in_zip)
                
                # 将缓冲区指针移到开始位置
                zip_buffer.seek(0)
                
                # 将内存中的ZIP文件添加到mail_Attachments
                mail_Attachments.append({
                    'name': f"{file_name}.zip",
                    'data': zip_buffer,
                    'is_file': False  # 标记为内存数据
                })

    return nolist, mail_Attachments


def create_email_template(recipient_email, df_html, attachments, MaximumAttachmentSize):
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email import encoders
    import os

    msg = MIMEMultipart()
    msg['Subject'] = '证书文件'
    msg['From'] = 'noreply@example.com'  # 替换为实际的发件人地址
    msg['To'] = recipient_email

    # 添加HTML内容
    msg.attach(MIMEText(df_html, 'html'))

    total_size = 0
    for attachment in attachments:
        # 获取文件大小
        if attachment['is_file']:
            file_size = os.path.getsize(attachment['path'])
        else:
            file_size = len(attachment['data'].getvalue())
        
        # 检查是否超过最大附件大小限制（将MB转换为字节）
        if total_size + file_size > MaximumAttachmentSize * 1024 * 1024:
            raise Exception(f"附件总大小超过限制：{MaximumAttachmentSize}MB")
        
        total_size += file_size

        # 创建附件部分
        part = MIMEBase('application', 'octet-stream')

        if attachment['is_file']:
            # 从文件读取数据
            with open(attachment['path'], 'rb') as f:
                part.set_payload(f.read())
        else:
            # 使用内存中的数据
            part.set_payload(attachment['data'].getvalue())

        # 编码附件
        encoders.encode_base64(part)
        # 添加头信息
        part.add_header(
            'Content-Disposition',
            f'attachment; filename="{attachment["name"]}"'
        )
        msg.attach(part)

    return msg


def process_and_create_email(df, pdf_path, recipient_email, df_html, MaximumAttachmentSize):
    """
    处理文件并创建邮件

    Args:
        df: DataFrame对象
        pdf_path: PDF文件路径
        pdfzip: ZIP文件输出路径
        recipient_email: 收件人邮箱
        df_html: HTML格式的邮件内容
        MaximumAttachmentSize: 最大附件大小限制

    Returns:
        dict: 包含处理结果的字典
    """
    try:
        res = create_zip_file(df, pdf_path)
        if len(res[1]) > 0:
            # 创建邮件
            outlook = win32.Dispatch('Outlook.Application')
            # 创建一封邮件
            mail = outlook.CreateItem(0)
            # 邮件收件人
            mail.To = recipient_email if recipient_email else ''
            # 获取当前邮件的签名（如果有）
            mail.Display()  # 显示邮件窗口，Outlook会自动加载签名
            signature = mail.HTMLBody  # 获取包含签名的当前HTMLBody

            head = """
                <head>
                <style>
                    body {
                        font-size: 14px;     /* 设置字体大小为5号（14px） */
                        font-family: 'SimSun', 'Microsoft YaHei', sans-serif;  /* 优先使用宋体 */
                        mso-font-alt: 'SimSun'; /* 强制指定宋体 */
                    }
                    table {
                            border-collapse: collapse;
                        }
                    th, td {
                        text-align: center;  /* 将文本居中 */
                        padding: 8px;        /* 添加一些内边距以改善可读性 */
                        
                    }
                    th {
                        background: #86A8E7;
                    }
                    td {
                        line-height: 7px;    /* 设置行高为10像素 */
                        height: 7px;         /* 设置单元格高度为10像素 */
                    }
                </style>
                </head>
                """
            custom_body = f"""
            <html>
            {head}
            <body>
            {df_html}
            </body>
            </html>
            """
            # 将自定义内容添加到签名前
            mail.HTMLBody = custom_body + signature

            MAX_ATTACHMENT_SIZE = MaximumAttachmentSize * 1024 * 1024  # 转换为字节
            total_size = 0

            # 处理附件
            for attachment in res[1]:
                if attachment['is_file']:
                    # 如果是文件路径
                    file_size = os.path.getsize(attachment['path'])
                    if total_size + file_size > MAX_ATTACHMENT_SIZE:
                        mail.Subject = f"文件大小超过{MaximumAttachmentSize}MB，无法添加附件"
                        print(f"文件大小超过{MaximumAttachmentSize}MB，无法添加附件")
                        break
                    total_size += file_size
                    mail.Attachments.Add(str(attachment['path']))
                else:
                    # 如果是内存中的数据
                    data_size = len(attachment['data'].getvalue())
                    if total_size + data_size > MAX_ATTACHMENT_SIZE:
                        mail.Subject = f"文件大小超过{MaximumAttachmentSize}MB，无法添加附件"
                        print(f"文件大小超过{MaximumAttachmentSize}MB，无法添加附件")
                        break
                    
                    # 创建临时文件并写入数据
                    temp_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'temp_attachments')
                    os.makedirs(temp_path, exist_ok=True)
                    temp_file = os.path.join(temp_path, attachment['name'])
                    
                    with open(temp_file, 'wb') as f:
                        f.write(attachment['data'].getvalue())
                    
                    total_size += data_size
                    mail.Attachments.Add(str(temp_file))
                    # 添加后立即删除临时文件
                    os.remove(temp_file)

            print(f"附件总大小：{total_size / 1024 / 1024}MB")
            
            # 显示邮件前预览
            mail.Display()
            
            return {
                "code": 200,
                "status": "ok",
                "message": "生成邮件成功",
                "data": res[0]
            }
        return {
            "code": 2004,
            "status": "no",
            "message": "没有找到pdf文件",
            "data": res[0]
        }
    except Exception as e:
        return {
            "code": 500,
            "status": "error",
            "message": str(e),
            "data": []
        }
